#
# global config options
#

# ----------------------------------------------------------------------------
# 转换路径
# 输出（绝对路径）：
# $(COMMON_PATH) = 项目和 RTK 的公共目录
# $(PRJ_PATH)    = 项目目录
# $(ROOT_PATH)   = RTK 目录
# $(OUT_COMMON)  = 输出目录
# $(OUT_DIR)     = 目标输出目录
# $(ARCH_PATH)   = 编译规目录
# $(BOARD_PATH)  = 开发板目录
# $(CHIP_PATH)   = 芯片目录
# ----------------------------------------------------------------------------
mkfile_path := $(abspath $(firstword $(MAKEFILE_LIST)))
mkfile_dir := $(dir $(mkfile_path))
mkfile_dir := $(mkfile_dir:%/=%)

override COMMON_PATH := $(abspath $(COMMON_PATH))
override PRJ_PATH := $(abspath $(PRJ_PATH))
override ROOT_PATH := $(abspath $(ROOT_PATH))
override ARCH_PATH := $(abspath $(ARCH_PATH))
override BOARD_PATH := $(abspath $(BOARD_PATH))
override CHIP_PATH := $(abspath $(CHIP_PATH))

# 兼容旧版本
ROOT_BASE := $(ROOT_PATH)
PRJ_ARCH := $(ARCH_PATH)
PRJ_BOARD := $(BOARD_PATH)
PRJ_CHIP := $(CHIP_PATH)

OUT_COMMON := $(PRJ_PATH)/outdir
OUT_DIR := $(OUT_COMMON)/$(notdir $(BOARD_PATH))

export COMMON_PATH
export PRJ_PATH
export ROOT_PATH
export ARCH_PATH
export BOARD_PATH
export CHIP_PATH
export OUT_DIR

# ----------------------------------------------------------------------------
# 编译选项：
# $(CC_PREFIX)  = 编译器前缀（由 build.sh 生成，作为参数输入）
# $(QUIET)      = 是否隐藏编译命令，控制 $(Q) 和 $(S)
# $(OPTIMIZE)   = 是否使用优化，由 cc.mk 使用
# $(PRJ_NAME)   = 输出项目文件名
# ----------------------------------------------------------------------------
CC_PREFIX ?= 
QUIET ?= y
OPTIMIZE ?= y
PRJ_NAME ?= $(notdir $(PRJ_PATH))

CP := cp -f
MD := mkdir -p

ifeq ($(QUIET), y)
  Q := @
  S := -s
endif

ifeq ($(shell uname | tr '[A-Z]' '[a-z]' | grep 'linux'),linux)
  ECHO := echo
else
  ECHO := echo -e
endif

export CC_PREFIX
export OPTIMIZE
export QUIET
export PRJ_NAME
export CP MD
export Q S ECHO


# ----------------------------------------------------------------------------
# 指定在固定目录 $(ROOT_PATH)/tools/bash/ 下的特定功能的脚本文件：
# $(FLASH_CONFIG) = 用于配置烧录算法的脚本
# $(FLASH_SCRIPT) = 用于 烧录、执行仿真连接服务 和 启动仿真连接服务 的脚本
# ----------------------------------------------------------------------------
FLASH_CONFIG ?= jlink_config.sh
FLASH_SCRIPT ?= jlink.sh

# ----------------------------------------------------------------------------
# config files
# 输出：
# $(CONF_FILE) = 所有的 .conf 文件路径
# ----------------------------------------------------------------------------
DEFAULT_CONF_FILE := $(wildcard $(BOARD_PATH)/*.conf) $(wildcard $(CHIP_PATH)/*.conf)
ifeq ($(CONF_FILE),)
  DEFAULT_CONF_FILE += $(wildcard $(PRJ_PATH)/*.conf)
endif

ifneq ($(EXT_CONF_FILE),)
  EXT_CONF_FILE := $(abspath $(EXT_CONF_FILE))
  EXT_CONF_FILE := $(filter-out $(OUT_COMMON)/%,$(EXT_CONF_FILE))
endif

override CONF_FILE := $(DEFAULT_CONF_FILE) $(CONF_FILE) $(filter-out $(CONF_FILE),$(EXT_CONF_FILE))

# ----------------------------------------------------------------------------
# makefiles
# ----------------------------------------------------------------------------
MK_FILE_CC := $(ARCH_PATH)/cc.mk
MK_FILE_LD := $(ARCH_PATH)/prj.mk
MK_FILE_IMG := $(ARCH_PATH)/img.mk

MK_MAKE_LIB := $(ROOT_PATH)/tools/make/lib.mk
MK_MAKE_SUB := $(ROOT_PATH)/tools/make/sub.mk

MK_FILE_SDK += $(wildcard $(BOARD_PATH)/*.mk $(CHIP_PATH)/*.mk $(PRJ_PATH)/*.mk $(ARCH_PATH)/*.mk)
MK_FILE_SDK := $(filter-out $(MK_FILE_CC) $(MK_FILE_LD) $(MK_FILE_IMG), $(MK_FILE_SDK))

export MK_FILE_CC

# ----------------------------------------------------------------------------
# include resource files for project
# ----------------------------------------------------------------------------
# include config files
# EXT_SYMBOLS :=
# EXT_INC_DIR :=
# EXT_INC_FILE :=
-include $(OUT_DIR)/autoconf.mk

# extra libraries
EXT_LIBS_DIR ?= $(ROOT_PATH)/library
EXT_LIBS_DIR := $(EXT_LIBS_DIR:%/=%)
LIBRARIES := $(wildcard $(ROOT_PATH)/library/*.a)
LIBRARIES += $(abspath $(shell [ -d $(ROOT_PATH)/library ] && find $(EXT_LIBS_DIR) -maxdepth 1 -not -path '*/.*' -iname "*.a" -type f))
ifneq ($(LIBRARIES),)
  LIBRARIES := -Wl,-start-group  $(LIBRARIES)  -Wl,-end-group
endif

EXT_INC_DIR := $(filter-out $(OUT_COMMON)/%,$(EXT_INC_DIR))
EXT_INC_DIR += $(OUT_DIR) $(ROOT_PATH)/include
EXT_INC_DIR := $(abspath $(EXT_INC_DIR))
EXT_INC_DIR := $(sort $(EXT_INC_DIR))

# include header file for all project
EXT_INC_FILE += autoconf.h
EXT_INC_FILE := $(EXT_INC_FILE:%=-include %)

# config symbols
AS_SYMBOLS := $(EXT_INC_DIR:%=-I%/) $(EXT_SYMBOLS)
CC_SYMBOLS := $(EXT_INC_DIR:%=-I%/) $(EXT_SYMBOLS) $(EXT_INC_FILE)
export AS_SYMBOLS
export CC_SYMBOLS
export EXT_SYMBOLS


PRJ-MK := $(addprefix $(COMMON_PATH)/,$(PRJ-MK))
PRJ-OUT := $(addprefix $(COMMON_PATH)/,$(PRJ-OUT))
SUB-MK := $(addprefix $(COMMON_PATH)/,$(SUB-MK))
SUB-OUT := $(addprefix $(COMMON_PATH)/,$(SUB-OUT))
LIB-MK := $(addprefix $(COMMON_PATH)/,$(LIB-MK))
LIB-OUT := $(addprefix $(COMMON_PATH)/,$(LIB-OUT))

OBJS-n := $(addprefix $(COMMON_PATH)/,$(OBJS-n))

CONF_INCLUDE := $(PRJ-INC-ALL-y) $(PRJ-INC-ALL-Y) $(SUB-INC-ALL-y) $(SUB-INC-ALL-Y) $(LIB-INC-ALL-y) $(LIB-INC-ALL-Y)
CONF_INCLUDE := $(addprefix $(COMMON_PATH)/,$(CONF_INCLUDE))
CONF_INCLUDE := $(foreach dir,$(shell [ -n "$(CONF_INCLUDE)" ] && find $(CONF_INCLUDE) -not -path '*/.*' -iname "*.h" -o -iname "*.hpp" -type f),$(dir $(dir)))
CONF_INCLUDE += $(addprefix $(COMMON_PATH)/,$(PRJ-INC-DIR-y) $(PRJ-INC-DIR-Y) $(SUB-INC-DIR-y) $(SUB-INC-DIR-Y) $(LIB-INC-DIR-y) $(LIB-INC-DIR-Y))
CONF_INCLUDE += $(PRJ_PATH) $(ARCH_PATH) $(BOARD_PATH) $(CHIP_PATH)
CONF_INCLUDE := $(sort $(CONF_INCLUDE:%/=%))

CONF_EXCLUDE := $(PRJ-INC-ALL-n) $(PRJ-INC-ALL-N) $(SUB-INC-ALL-n) $(SUB-INC-ALL-N) $(LIB-INC-ALL-n) $(LIB-INC-ALL-N)

PRJ_INCLUDE := $(PRJ_PATH) $(foreach dir,$(shell find $(PRJ_PATH) $(BOARD_PATH) -not -path '*/.*' -iname "*.h" -o -iname "*.hpp" -type f),$(dir $(dir)))
ifneq ($(strip $(CONF_EXCLUDE)),)
  PRJ_INCLUDE := $(filter-out $(addprefix $(COMMON_PATH)/,$(CONF_EXCLUDE))/%,$(PRJ_INCLUDE)) $(CONF_INCLUDE)
endif
PRJ_INCLUDE := $(sort $(PRJ_INCLUDE))
PRJ_INCLUDE := $(filter-out $(OUT_COMMON)/% $(addsuffix /%,$(PRJ-OUT)) $(addsuffix /%,$(SUB-OUT)) $(addsuffix /%,$(LIB-OUT)),$(PRJ_INCLUDE))
PRJ_INCLUDE := $(PRJ_INCLUDE:%/=%)
PRJ_INCLUDE := $(PRJ_INCLUDE:%=-I%/)
INCLUDE_PATHS := $(PRJ_INCLUDE) $(filter-out $(addsuffix %,$(PRJ_INCLUDE)) $(EXT_INC_DIR), $(CONF_INCLUDE:%=-I%/))
export INCLUDE_PATHS


sub_objs-y += $(addprefix $(COMMON_PATH)/,$(SUB-SRC-y) $(SUB-SRC-Y))
sub_objs-y := $(filter-out $(OBJS-n) $(OUT_COMMON)/% $(addsuffix /%,$(SUB-OUT)),$(sub_objs-y))
sub_objs-y := $(addsuffix .o,$(sub_objs-y))
sub_objs-y := $(sort $(sub_objs-y))
SUB_OBJS := $(sub_objs-y:$(COMMON_PATH)/%=$(OUT_DIR)/%)
export SUB_OBJS

lib_objs-y += $(addprefix $(COMMON_PATH)/,$(LIB-SRC-y) $(LIB-SRC-Y))
lib_objs-y := $(filter-out $(OBJS-n) $(OUT_COMMON)/% $(addsuffix /%,$(LIB-OUT)),$(lib_objs-y))
lib_objs-y := $(addsuffix .o,$(lib_objs-y))
lib_objs-y := $(sort $(lib_objs-y))
LIB_OBJS := $(lib_objs-y:$(COMMON_PATH)/%=$(OUT_DIR)/%)
export LIB_OBJS

CONF_PRJ := $(dir $(filter $(COMMON_PATH)/%, $(PRJ-MK) $(SUB-MK) $(LIB-MK)))
objs-y := $(filter-out $(addsuffix %,$(CONF_PRJ)), $(shell find $(PRJ_PATH) $(BOARD_PATH) -not -path '*/.*' -iname "*.[cs]" -o -iname "*.asm" -o -iname "*.cpp" -type f))
objs-y += $(addprefix $(COMMON_PATH)/,$(PRJ-SRC-y) $(PRJ-SRC-Y))
objs-y := $(filter-out $(OBJS-n) $(OUT_COMMON)/% $(addsuffix /%,$(PRJ-OUT)),$(objs-y) $(ext-objs-y))
objs-y := $(addsuffix .o,$(objs-y))
objs-y := $(sort $(objs-y) $(sub_objs-y) $(lib_objs-y))
PRJ_OBJS := $(objs-y:$(COMMON_PATH)/%=$(OUT_DIR)/%)
PRJ_OBJS := $(filter-out $(SUB_OBJS) $(LIB_OBJS),$(PRJ_OBJS))

OBJS := $(PRJ_OBJS) $(SUB_OBJS) $(LIB_OBJS)

SUB_CC := $(addsuffix .CC,$(SUB-MK))
SUB_CLEAN := $(addsuffix .CLEAN,$(SUB-MK))

LIB_CC := $(addsuffix .CC,$(LIB-MK))
LIB_CLEAN := $(addsuffix .CLEAN,$(LIB-MK))
LIB_INSTALL := $(addsuffix .AR,$(LIB-MK))
LIB_UNINSTALL := $(addsuffix .RM,$(LIB-MK))

# ----------------------------------------------------------------------------
# release file name
# ----------------------------------------------------------------------------
ifneq ($(findstring release,$(MAKECMDGOALS)),)
  GIT_TIME := $(shell cd $(PRJ_PATH) && git log -1 --format="%at" | xargs -I{} date -d @{} +%Y%m%d_%H%M)
  GIT_HASH := $(shell cd $(PRJ_PATH) && git -C ${PRJ_PATH} log -1 --format="%h")
  GIT_DIRTY := $(shell cd $(PRJ_PATH) && git status --porcelain)
  
  ifeq ($(strip $(GIT_DIRTY)),)
    RELEASE_PREFIX := Release
  else
    RELEASE_PREFIX := Test
  endif
  
  RELEASE_FILE := $(PWD)/release/$(RELEASE_PREFIX)-$(PRJ_NAME)-$(notdir $(BOARD_PATH))-$(GIT_TIME)-$(GIT_HASH)
endif

# ----------------------------------------------------------------------------
# Phony
# ----------------------------------------------------------------------------
.PHONY: \
	help \
	all objdump size clean \
	image image_clean \
	build build_clean debug_build \
	lib lib_clean \


all:
ifeq ($(mset),)
	$(Q)$(MAKE) $(S) -C $(mkfile_dir) help prj size
else
	@$(ROOT_PATH)/tools/bash/mset_log.sh $(ROOT_PATH) $(OUT_DIR) $(mset) $($(mset))
endif

help:
ifeq ($(MAKECMDGOALS),)
	@$(ECHO) "  MAKE    \033[33m$(.DEFAULT_GOAL)\033[0m"
else ifeq ($(MAKECMDGOALS),help)
	@$(ECHO) "#"
	@$(ECHO) "#\033[33m  all: \033[0m           默认目标，编译项目源码(不含库源码)，输出 .bin 文件"
	@$(ECHO) "#\033[33m  clean: \033[0m         删除所有由目标 'all' 生成的所有文件"
	@$(ECHO) "#"
	@$(ECHO) "#\033[33m  image: \033[0m         执行 'all' 并制作镜像文件。镜像文件根据配置，分为 bootloader 和 app 两种类型，分别作出两种行为:"
	@$(ECHO) "#                  bootloader: 'all' 所生成的 .bin 文件及相关文件一并复制到文件夹 bin 中"
	@$(ECHO) "#                  app: 合并工程的所有文件及 'bootloader' 所生成的 .bin 文件，生成最终的一个镜像文件"
	@$(ECHO) "#\033[33m  image_clean: \033[0m   删除所有由目标 'image' 生成的所有文件"
	@$(ECHO) "#"
	@$(ECHO) "#\033[33m  sub: \033[0m           仅编译子模块(不含项目源码)，生成的中间文件可被 'all' 连接"
	@$(ECHO) "#\033[33m  sub_clean: \033[0m     删除所有由目标 'sub' 生成的所有中间文件"
	@$(ECHO) "#"
	@$(ECHO) "#\033[33m  lib: \033[0m           编译库源码(不含项目源码)，生成的中间文件可被 'all' 连接"
	@$(ECHO) "#\033[33m  lib_clean: \033[0m     删除所有由目标 'lib' 生成的所有中间文件"
	@$(ECHO) "#\033[33m  lib_install: \033[0m   执行 'lib' 并生成静态库"
	@$(ECHO) "#\033[33m  lib_uninstall: \033[0m 删除所有由目标 'lib_install' 生成的静态库(不含中间文件)"
	@$(ECHO) "#"
	@$(ECHO) "#\033[33m  build: \033[0m         执行 'lib', 'all' 和'image'"
	@$(ECHO) "#\033[33m  debug_build: \033[0m   执行 'lib', 'all' 和'image', OPTIMIZE=n 以方便调试"
	@$(ECHO) "#\033[33m  build_clean: \033[0m   删除所有由目标 'build' 生成的所有文件(输出目录除外)。"
	@$(ECHO) "#"
	@$(ECHO) "#\033[33m  flash: \033[0m         通过 JLink 烧写程序到目标板"
	@$(ECHO) "#\033[33m  flash_config: \033[0m  配置 JLink 的 FLASH 烧录算法"
	@$(ECHO) "#\033[33m  debug_server: \033[0m  启动 JLinkGDBServer"
	@$(ECHO) "#"
	@$(ECHO) "#\033[33m  objdump: \033[0m       生成反汇编。"
	@$(ECHO) "#"
	@$(ECHO) "#\033[33m  release: \033[0m       执行 'build', 输出释放文件到 ./release/Release-prj-board-date-commit.*。"
	@$(ECHO) "#"
	@$(ECHO) "#\033[33m  mset: \033[0m          打印变量值。如 make mset=MAKEFILE_LIST"
	@$(ECHO) "#"
else
	@$(ECHO) "  MAKE    \033[33m$(MAKECMDGOALS)\033[0m"
endif

# project config files
$(OUT_DIR)/autoconf.mk: $(CONF_FILE) $(filter-out $(OUT_DIR)/autoconf.mk,$(MAKEFILE_LIST))
ifneq ($(MAKECMDGOALS),clean)
	@$(ROOT_PATH)/tools/bash/gen_config_mk.sh $(COMMON_PATH) $(PRJ_PATH) $(ROOT_PATH) $@ $(CONF_FILE)
endif

$(CONF_FILE):
	$(error No such of CONF_FILE '$@'')


# ----------------------------------------------------------------------------
# Include project rules
# ----------------------------------------------------------------------------
-include $(MK_FILE_LD)


# ----------------------------------------------------------------------------
# sub rules
# ----------------------------------------------------------------------------
sub: help $(SUB_CC)

sub_clean: help $(SUB_CLEAN)

$(ROOT_PATH)%.sub.mk.CC:
	$(Q)$(MAKE) $(S) -f $(MK_MAKE_SUB) cc MKFILE=$(basename $@)

$(ROOT_PATH)%.sub.mk.CLEAN:
	$(Q)$(MAKE) $(S) -f $(MK_MAKE_SUB) cc_clean MKFILE=$(basename $@)


# ----------------------------------------------------------------------------
# lib rules
# ----------------------------------------------------------------------------
lib: help $(LIB_CC)

lib_clean: help $(LIB_CLEAN)

lib_install: help $(LIB_INSTALL)

lib_uninstall: help $(LIB_UNINSTALL)

$(ROOT_PATH)%.lib.mk.CC:
	$(Q)$(MAKE) $(S) -f $(MK_MAKE_LIB) cc MKFILE=$(basename $@)

$(ROOT_PATH)%.lib.mk.CLEAN:
	$(Q)$(MAKE) $(S) -f $(MK_MAKE_LIB) cc_clean MKFILE=$(basename $@)

$(ROOT_PATH)%.lib.mk.AR:
	$(Q)$(MAKE) $(S) -f $(MK_MAKE_LIB) ar MKFILE=$(basename $@)

$(ROOT_PATH)%.lib.mk.RM:
	$(Q)$(MAKE) $(S) -f $(MK_MAKE_LIB) ar_clean MKFILE=$(basename $@)



# ----------------------------------------------------------------------------
# build rules
# ----------------------------------------------------------------------------
build: help
	$(MAKE) $(S) CC_SYMBOLS+=-DBUILD_TYPE_PRJ=1 -f$(mkfile_path) $(PRJ_OBJS)
ifneq ($(SUB_CC),)
	@$(ECHO) "  MAKE    \033[33mSUB_CC\033[0m"
	$(MAKE) $(S) CC_SYMBOLS+=-DBUILD_TYPE_SUB=1 -f$(mkfile_path) $(SUB_CC)
endif
ifneq ($(LIB_CC),)
	@$(ECHO) "  MAKE    \033[33mLIB_CC\033[0m"
	$(MAKE) $(S) CC_SYMBOLS+=-DBUILD_TYPE_LIB=1 -f$(mkfile_path) $(LIB_CC)
endif
	$(MAKE) $(S) -f$(mkfile_path) install $(HEX_FILE) size image
	$(ECHO) "cksum: \c" && cksum $(ELF_FILE_PATH:$(shell pwd)/%=%)
	$(ECHO) "[\033[32mSUCCESS\033[0m]\n"

debug_build: help
	$(MAKE) $(S) -f$(mkfile_path) OPTIMIZE=n $(PRJ_OBJS)
ifneq ($(SUB_CC),)
	@$(ECHO) "  MAKE    \033[33mSUB_CC\033[0m"
	$(MAKE) $(S) -f$(mkfile_path) OPTIMIZE=n $(SUB_CC)
endif
ifneq ($(LIB_CC),)
	@$(ECHO) "  MAKE    \033[33mLIB_CC\033[0m"
	$(MAKE) $(S) -f$(mkfile_path) OPTIMIZE=n $(LIB_CC)
endif
	$(MAKE) $(S) -f$(mkfile_path) install $(HEX_FILE) size image
	$(ECHO) "cksum: \c" && cksum $(ELF_FILE_PATH:$(shell pwd)/%=%)
	$(ECHO) "[\033[32mSUCCESS\033[0m]\n"

build_clean: help install_clean
	$(Q)$(RM) -r $(OUT_DIR)


# ----------------------------------------------------------------------------
# download rules
# ----------------------------------------------------------------------------
flash: $(BIN_FILE) image help
	@$(ROOT_PATH)/tools/bash/$(FLASH_SCRIPT) flash $(BIN_FILE)

debug_server:
	@$(ROOT_PATH)/tools/bash/$(FLASH_SCRIPT) debugserver

debug_server_run:
	@$(ROOT_PATH)/tools/bash/$(FLASH_SCRIPT) debugserver_run

debug_cmd:
	@$(ROOT_PATH)/tools/bash/$(FLASH_SCRIPT) debugcmd

flash_config:
	@$(ROOT_PATH)/tools/bash/$(FLASH_CONFIG)


# ----------------------------------------------------------------------------
# release output
# ----------------------------------------------------------------------------
release: build image_release


# ----------------------------------------------------------------------------
# var test
# ----------------------------------------------------------------------------
mset:
	@$(ECHO) "\033[33m提示:\033[0m 打印变量的值使命令如 'make mset=MAKEFILE_LIST'"
	@$(ECHO) "如果该值非空, 将自动生成新命令到 mset_log.mk 中"

-include $(OUT_DIR)/mset_log.mk
